package com.wxmit.system.base.core;

import cn.dev33.satoken.stp.StpUtil;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wxmit.base.domain.ApiResult;
import com.wxmit.base.util.DateUtils;
import com.wxmit.base.util.JsonUtils;
import com.wxmit.base.util.ServletUtils;
import com.wxmit.base.util.StringUtils;
import com.wxmit.base.validate.AddGroup;
import com.wxmit.base.validate.UpdateGroup;
import com.wxmit.framework.web.operatelog.Log;
import com.wxmit.framework.web.operatelog.LogModule;
import com.wxmit.framework.web.operatelog.enums.BusinessType;
import com.wxmit.system.base.domain.PageDTO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.groups.Default;
import java.beans.PropertyEditorSupport;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Serializable;
import java.net.URLEncoder;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * @Description ShushanBaseController
 * @Author huangxiong
 * @Date 2022/7/22 12:59
 * @Version V1.0
 */
public class ShushanBaseController<S extends IShushanService<T>,T,ID extends Serializable> {

    protected final Logger logger = LoggerFactory.getLogger(ShushanBaseController.class);

    // Page 所需
    private final String PAGE_PARAM = "page";
    private final String SEARCH_DATA_PARAM = "searchData";

    //Permission
    public final String PERMISSION_PREFIX;
    public final Boolean needCheckPermission;

    //Service
    public final S baseService;

    public ShushanBaseController(S baseService){
        this(baseService,null);
    }

    public ShushanBaseController(S baseService,String permissionPrefix){
        this.baseService = baseService;
        PERMISSION_PREFIX = permissionPrefix;
        needCheckPermission = Objects.nonNull(permissionPrefix);
    }
    /**
     * 将前台传递过来的日期格式的字符串，自动转化为Date类型
     */
    @InitBinder
    public void initBinder(WebDataBinder binder)
    {
        // Date 类型转换
        binder.registerCustomEditor(Date.class, new PropertyEditorSupport()
        {
            @Override
            public void setAsText(String text)
            {
                setValue(DateUtils.parseDate(text));
            }
        });
    }


    @GetMapping("/{id:\\d+}")
    public ApiResult<T> get(@PathVariable ID id){
        checkPermission(BusinessType.INFO);
        beforeGet(id);
        T domain = baseService.getById(id);
        afterGet(domain);
        return ApiResult.successWithData(domain);
    }

    @PostMapping("/list")
    public ApiResult<IPage<T>> listPage(@RequestBody PageDTO<T> pageDTO){
        checkPermission(BusinessType.LIST);
        beforeList(pageDTO);

        IPage<T> result = baseService.listPage(pageDTO);
        afterList(result);
        return ApiResult.successWithData(result);
    }

    @Log(name = "新增操作",type = BusinessType.INSERT)
    @PostMapping
    public ApiResult add(@RequestBody @Validated({AddGroup.class, Default.class}) T domain){
        checkPermission(BusinessType.INSERT);
        beforeAdd(domain);
        boolean result = baseService.save(domain);
        afterAdd(domain,result);
        return ApiResult.success();
    }

    @Log(name = "更新操作",type = BusinessType.UPDATE)
    @PutMapping
    public ApiResult update(@RequestBody @Validated({UpdateGroup.class, Default.class}) T domain){
        checkPermission(BusinessType.UPDATE);
        beforeUpdate(domain);
        boolean result = baseService.updateById(domain);
        afterUpdate(domain,result);
        return ApiResult.success();
    }

    @Log(name = "更新操作",type = BusinessType.DELETE)
    @DeleteMapping("/{ids}")
    public ApiResult del(@PathVariable List<ID> ids){
        checkPermission(BusinessType.DELETE);
        beforeDel(ids);
        boolean result = baseService.removeByIds(ids);
        afterDel(ids,result);
        return ApiResult.success();
    }


    public <ET> void responseExcel(HttpServletResponse response,String name, Class<ET> clazz, List<ET> records) throws IOException {
        setUpExportExcelResponse(response,name);
        EasyExcel.write(response.getOutputStream(),clazz).sheet(name).doWrite(records);
    }

    public void setUpExportExcelResponse(HttpServletResponse response,String name)throws IOException{
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        // 这里URLEncoder.encode可以防止中文乱码
        String fileName = URLEncoder.encode(name, "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
    }


    protected void beforeGet(ID id){
        //DO NOTHING...
    }
    protected void afterGet(T domain){
        //DO NOTHING...
    }
    protected void beforeList(PageDTO<?> pageDTO){
        //DO NOTHING...
    }
    protected void afterList(IPage<T> result){
        //DO NOTHING...
    }
    protected void beforeAdd(T domain){
        //DO NOTHING...
    }
    protected void afterAdd(T domain,boolean result){
        Assert.isTrue(result,"新增失败,请刷新后重试！");
    }
    protected void beforeUpdate(T domain){
        //DO NOTHING...
    }
    protected void afterUpdate(T domain,boolean result){
        Assert.isTrue(result,"更新失败,请刷新后重试！");
    }
    protected void beforeDel(List<ID> ids){
        //DO NOTHING...
    }
    protected void afterDel(List<ID> ids,boolean result){
        Assert.isTrue(result,"删除失败,请刷新后重试！");
    }

    protected void checkPermission(BusinessType businessType) {
        if(!needCheckPermission)return;
        switch (businessType){
            case LIST:
                StpUtil.checkPermission( mergePermission("list") );
                break;
            case INFO:
                StpUtil.checkPermission( mergePermission("query") );
                break;
            case INSERT:
                StpUtil.checkPermission( mergePermission("add") );
                break;
            case UPDATE:
                StpUtil.checkPermission( mergePermission("edit") );
                break;
            case DELETE:
                StpUtil.checkPermission( mergePermission("remove") );
                break;
        }
    }
    private String mergePermission(String permissionStr){
        return PERMISSION_PREFIX + permissionStr;
    }
}

